﻿using BlockOS.Server.FileIO;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using ZerAx.ObjectNotation;

namespace BlockOS.Server
{
    public class FileManager : IServerModule
    {
        private readonly string levelPath;

        private ConcurrentQueue<IFileTask> sendQueue, receiveQueue;

        private Thread taskRunner;
        private ManualResetEvent hasTask;
        private volatile bool isTaskRunnerRunning;

        private GameServer server;

        public FileManager(GameServer server, string levelPath)
        {
            this.server = server;
            this.levelPath = levelPath;
            taskRunner = new(IOThread);
            sendQueue = new();
            receiveQueue = new();
            hasTask = new(false);
        }

        public void Init()
        {
            if (!Directory.Exists(levelPath))
            {
                Directory.CreateDirectory(levelPath);
            }
            isTaskRunnerRunning = true;
            taskRunner.Start();
        }

        public void RequestRead<T>(string path, Func<Stream, T> read, Action<T> done)
        {
            sendQueue.Enqueue(new ReadTask<T>(path, read, done));
            hasTask.Set();
        }

        public void RequestWrite(string path, Action<Stream> write, Action done)
        {
            sendQueue.Enqueue(new WriteTask(path, write, done));
            hasTask.Set();
        }

        public void Tick()
        {
            while (receiveQueue.TryDequeue(out var task))
            {
                task.Done();
            }
        }

        public void Deinit()
        {
            isTaskRunnerRunning = false;
            hasTask.Set();
        }

        private void IOThread()
        {
            while (true)
            {
                hasTask.WaitOne();
                if (!isTaskRunnerRunning) break;

                receiveQueue.Enqueue(new WriteTask(null, null, () => { server.LogMessage("Recv Msg"); }));

                if (sendQueue.TryDequeue(out var task))
                {
                    using var file = File.Open(task.FileName, FileMode.OpenOrCreate, task is WriteTask ? FileAccess.Write : FileAccess.Read);
                    task.Run(file);

                    receiveQueue.Enqueue(task);
                }

                if (sendQueue.Count <= 0)
                {
                    hasTask.Reset();
                }
            }
        }

        public void Update(TimeSpan deltaTime)
        {

        }
    }
}
